#pragma once

class CogOpInfo;
class CogParameterizedOp;
class CogEvaluator;
template <class TD, class PD> class CogProcessor;
template <class TD, class PD> class CogSampledEvaluator;
template <class TD> class CogStackData;
template <class TD> class CogStackProcessor;
class CogProduction; // pointer only

#include "CogBase.h"

// ------------------------------------------------------------------------------------------

// stack ops
#define OP_NONE		0
#define OP_VALUE	1
#define OP_PIN		2
#define OP_POUT		3

// parameterized ops
#define OP_VAR		4
#define OP_CONST	5
#define OP_PARAMETER 1000

// -------------------

class CogOpInfo
{
public:
	CogOpInfo() {}
	CogOpInfo(string _label, size_t _prec) : label(_label), precedence(_prec) {}

	string label;
	size_t precedence;
};

// -------------------

class CogParameterizedOp
{
public:
	CogParameterizedOp(bool _var, size_t _index) : isVariable(_var), index(_index) {}

	bool isVariable;
	size_t index;
};

// -------------------

template <class TD>
class CogCachedResult
{
public:
	CogCachedResult() : empty(true) {}

	bool empty;
	TD value;
};

// -------------------

typedef uint32_t CogCacheMode;
const CogCacheMode COGCM_OFF = 0x00000000;
const CogCacheMode COGCM_VALUE = 0x00000001;
const CogCacheMode COGCM_STACK = 0x00000002;

// ------------------------------------------------------------------------------------------

class CogEvaluator
{
public:
	CogEvaluator();
	virtual ~CogEvaluator();

	virtual bool getId(const string& label, uint32_t& id);
	virtual bool getLabel(uint32_t id, string& label);
	virtual bool readParameter(size_t opId, const string& value) { return false; }

	virtual size_t getCacheOffset() { return 0; }
	virtual size_t setCacheOffset(size_t offset) { return offset; }
	virtual void constructCache(char* pCache) {}
	virtual void destroyCache(char* pCache) {}
	CogCacheMode getCacheMode() { return cacheMode; }
	void setCacheMode(CogCacheMode mode) { cacheMode = mode; }

	virtual double evaluate(CogProduction* pRule) = 0;
	virtual void reset() {}

protected:
	map<uint32_t, CogOpInfo> validOps;
	uint32_t paraSymbolIdx;
	CogCacheMode cacheMode;
};

// ------------------------------------------------------------------------------------------

template <class TD, class PD>
class CogProcessor : virtual public CogEvaluator
{
public:
	virtual void pushOperator(size_t id, PD& data) = 0;
	virtual void pushValuePtr(TD* pValue, PD& data) = 0;
	virtual TD process(PD& data, size_t valC = 0) = 0;
protected:
	virtual void merge(PD& original, PD& extension) = 0;
	//virtual TD processOperator(size_t id, PD& data) = 0;
};

// ------------------------------------------------------------------------------------------

template <class TD, class PD>
class CogSampledEvaluator : virtual public CogProcessor<TD, PD>
{
public:
	CogSampledEvaluator();
	virtual ~CogSampledEvaluator();
	
	virtual size_t getCacheOffset() { return cacheOffset; }
	virtual size_t setCacheOffset(size_t offset);
	virtual void constructCache(char* pCache);
	virtual void destroyCache(char* pCache);

	virtual double evaluate(CogProduction* pRule);
	virtual void reset();
	TD target();
	bool first();
	bool next();

	virtual double error(TD value) = 0;
	
protected:
	void expand(CogProduction* pRule, PD& data);
	TD* computeData(CogProduction* pRule);
	void computeExpand(CogProduction* pRule, PD& data);
	PD* collectData(CogProduction* pRule);
	void collectExpand(CogProduction* pRule, PD& data);
	void rootExpand(CogProduction* pRule, PD& data);

	// data:
	vector<TD> targets;
	boost::thread_specific_ptr<size_t> cCaseIdx;
	size_t cacheOffset;
};

// ------------------------------------------------------------------------------------------

template <class TD>
class CogStackData
{
public:
	stack<size_t> symbolStack;
	list<size_t> rpnQueue;
	list<TD*> valuePtrQueue; // used like a queue for the most part...
};

// --------------

template <class TD>
class CogStackProcessor : virtual public CogProcessor<TD, CogStackData<TD>>
{
public:
	CogStackProcessor();

	void pushOperator(size_t id, CogStackData<TD>& data);
	void pushValuePtr(TD* pValue, CogStackData<TD>& data);
	TD process(CogStackData<TD>& data, size_t valC = 0);
protected:
	virtual TD processOperator(size_t id, stack<TD>& result) = 0;
	void merge(CogStackData<TD>& original, CogStackData<TD>& extension);
	
};

// ------------------------------------------------------------------------------------------
